package maosy.lib.valid;

import maosy.lib.valid.annotations.ParamValid;
import maosy.lib.valid.exception.ParamException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.stereotype.Component;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Aspect
@Component
public class ParamValidAspect {

    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();


    @Before(value = "@annotation(pv)")
    public void paramValid(JoinPoint point, ParamValid pv) {
        // 获得切入方法参数
        Object[] args = point.getArgs();
        // 获得切入的方法
        Method method = ((MethodSignature) point.getSignature()).getMethod();

        if (args != null && args[0] != null) {
            // 执行校验，获得校验结果
            Set<ConstraintViolation<Object>> validResult = validator.validate(args[0], pv.value());

            if (!validResult.isEmpty()) {
                // 获得方法的参数名称
                List<String> errors = validResult.stream().map(constraintViolation -> {
                    // 获得校验的参数路径信息
                    PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();
                    // 获得校验的参数位置
                    String paramName = pathImpl.getLeafNode().getName();
                    // 获得校验的参数名称
                    return paramName == null ?
                            constraintViolation.getMessage() :
                            paramName + "=" + constraintViolation.getMessage();
                }).collect(Collectors.toList());
                throw new ParamException("参数校验错误", errors);
            }
        }
    }
}
